package com.linc.concurrency.effectiveDemo;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class Memoizer3<A, V> implements Computable<A, V> {
  private final Map<A, Future<V>> cache = new HashMap<>();
  private final Computable<A, V> c;

  public Memoizer3(Computable<A, V> c) {
    this.c = c;
  }

  @Override
  public V compute(A args) throws InterruptedException {
    Future<V> f = cache.get(args);
    if (f == null) {
      Callable<V> eval = () -> c.compute(args);
      FutureTask<V> ft = new FutureTask<>(eval);
      f = ft;
      cache.put(args, ft);
      ft.run();
    } else {
      System.out.println("find in cache.");
    }
    try {
      return f.get();
    } catch (ExecutionException e) {
      var cause = e.getCause();
      if (cause instanceof Error) throw (Error) cause;
      else if (cause instanceof RuntimeException) throw (RuntimeException) cause;
      else throw new IllegalStateException("unchecked", e);
    }
  }
}
